#ifndef UDPClient__h_
#define UDPClient__h_

#define HEADER_ONLY
#include  "../Os Abstraction/OS_TCPIP.h"
#include  "../Os Abstraction/OS_Task.h"
#include  "../Os Abstraction/OS_Event.h"
#include  "../Os Abstraction/OS_Semaphore.h"


#include <queue>

typedef enum _eUDPClientReturnCode_t
{
	UDPServer_ReturnCode_Ok,
	UDPServer_ReturnCode_NotInitialized,
	UDPServer_ReturnCode_TxFailed,	
	UDPServer_ReturnCode_RemoteIPNotSet,	
}eUDPClientReturnCode_t;

class CUDPClient
{
public:

	CUDPClient();
	~CUDPClient();

	CUDPClient & SetRemoteIP(const std::string & sIP);
	CUDPClient & SetInLocalPort(unsigned short usPort);
	CUDPClient & SetOutRemotePort(unsigned short usPort);
	CUDPClient & Connect();
	CUDPClient & Disconnect();

	bool WaitUntilConnected(uint32_t timeout);

	void Process();

	typedef enum _TransmitOptions_t
	{
		TransmitOptions_Broadcast = 1,	
	}TransmitOptions_t;
	
	typedef eUDPClientReturnCode_t eReturnCode_t;
	
	eReturnCode_t Transmit(const uint8_t *txdata,unsigned int iLen,unsigned int iOptions);
	unsigned long Read(uint8_t * pData,unsigned long ulCapacity,uint32_t &ulIP);
	bool HasData();
	bool WaitForRxData(unsigned long iTimeoutMs);

	static std::string ToString(const CUDPClient::eReturnCode_t & er);

private:
	
	CUDPClient(const CUDPClient & rhs){}
	CUDPClient & operator = (const CUDPClient & rhs){ return *this;}

	//static DWORD WINAPI RxThreadCaller( LPVOID lpParam ) ;
	//DWORD WINAPI RxThreadCaller();
	static unsigned int RxThreadCaller( void * lpParam );
	unsigned int RxThreadCaller();

	void CloseSockets();
	int PollRxSocket(int timeoutMs);

	bool StartRxThread();
	void StopRxThread();

	void ClearRxData();

	enum
	{
		eMark,
		eInitializing,
		eInitialized,
		eReading,
		eFail,
	}eState;

	SOCKET m_InSocket;
	SOCKET m_OutSocket;
	SOCKET m_BroadcastOutSocket;
	std::string m_sRemoteIP;
	unsigned short m_usOutRemotePort;
	unsigned short m_usInRemotePort;

	bool m_bVerbose;

	OS_Event * m_StopRxThread;
	OS_Event * m_HasStoppedRxThread;
	OS_Event * m_IsRunning;
	OS_Task * m_RxThread;

	OS_Event * m_RxDataEvent;
	OS_Event * m_Conneced;

	typedef struct _RxDatagram
	{
		unsigned char Data[2048];
		unsigned long Len;
		unsigned long Ip;
	}RxDatagram;

	OS_Semaphore *m_RxCs;

	std::queue<RxDatagram> m_RxDatagrams;
};

#endif // UDPClient__h_

